﻿//-----------------------------------------------------------------------
// <copyright file="EntityHelper.cs" company="NECSV">
//     Copyright (c) NECSV. All rights reserved.
// </copyright>
// <summary>The helper class uses for getting and setting value from database to entity object.</summary>
//-----------------------------------------------------------------------
namespace LMT.Db.OracleClient
{
    using System.Data.Common;
    using System.Data.OracleClient;
    using System;
    using System.Reflection;

    /// <summary>
    /// The helper class uses for getting and setting value from database to entity object.
    /// </summary>
    public class OracleEntity : EntityProvider
    {
        /// <summary>
        /// 
        /// </summary>
        private static OracleEntity entity;

        /// <summary>
        /// Gets the instance.
        /// </summary>
        public static OracleEntity Instance
        {
            get
            {
                if (OracleEntity.entity == null)
                {
                    OracleEntity.entity = new OracleEntity();
                }

                return OracleEntity.entity;
            }
        }

        /// <summary>
        /// Prevents a default instance of the <see cref="OracleEntity"/> class from being created.
        /// </summary>
        private OracleEntity()
        {
        }

        /// <summary>
        /// Creates the parameter.
        /// </summary>
        /// <param name="para">The para.</param>
        /// <param name="colAtt">The col att.</param>
        /// <returns></returns>
        protected override DbParameter OnCreateParameter(DbColumn colAtt, string paraPrefix)
        {
            OracleParameter oraclePara = null;

            if (colAtt.ColumSize > 0)
            {
                oraclePara = new OracleParameter(paraPrefix + colAtt.ColumName, (OracleType)colAtt.DbType, colAtt.ColumSize);
            }
            else
            {
                oraclePara = new OracleParameter(paraPrefix + colAtt.ColumName, (OracleType)colAtt.DbType);
            }

            return oraclePara;
        }

        /// <summary>
        /// Called when [generate insert query].
        /// </summary>
        /// <param name="colAtt">The col att.</param>
        /// <returns></returns>
        protected override string OnGenerateInsertPhase(DbColumn colAtt)
        {
            return colAtt.IsUseSysDate ? "sysdate," : string.Format(":{0},", colAtt.ColumName);//"?,");
        }

        /// <summary>
        /// Called when [generate set query].
        /// </summary>
        /// <param name="colAtt">The col att.</param>
        /// <param name="paraPrefix">The para prefix.</param>
        /// <returns></returns>
        protected override string OnGenerateSetPhase(DbColumn colAtt, string paraPrefix)
        {
            if (colAtt.IsUseSysDate)
            {
                return colAtt.ColumName + " = sysdate,";
            }
            else
            {
                return string.Format("{1} = :{0}{1},", paraPrefix, colAtt.ColumName);
            }
        }

        /// <summary>
        /// Called when [generate where query].
        /// </summary>
        /// <param name="colAtt">The col att.</param>
        /// <param name="paraPrefix">The para prefix.</param>
        /// <returns></returns>
        protected override string OnGenerateWherePhase(DbColumn colAtt)
        {
            return string.Format("{0} = :{0} AND ", colAtt.ColumName);
        }

        /// <summary>
        /// Called when [generate query string].
        /// </summary>
        /// <param name="colAtt">The col att.</param>
        /// <param name="condi">The condi.</param>
        /// <param name="columnAlias">The column alias.</param>
        /// <returns></returns>
        protected override string OnGenerateWherePhase(DbColumn colAtt, Condition condi, string columnAlias)
        {
            if (condi.IsCompareDateOnly)
            {
                if (condi.Compare == Operator.Between)
                {
                    return string.Format(" ( TRUNC({0}) {1} to_date(:{2}_1, 'yyyy-MM-dd') AND to_date(:{2}_2, 'yyyy-MM-dd') ) ", columnAlias, condi.OperatorQuery, colAtt.ColumName);// + " = ? AND ");
                }
                else
                {
                    return string.Format(" TRUNC({0}) {1} to_date(:{2}, 'yyyy-MM-dd') ", columnAlias, condi.OperatorQuery, colAtt.ColumName);// + " = ? AND ");
                }
            }
            else
            {
                if (condi.Compare == Operator.Between)
                {
                    return string.Format(" ( {0} {1} :{2}_1 AND :{2}_2 ) ", columnAlias, condi.OperatorQuery, colAtt.ColumName);// + " = ? AND ");
                }
                else
                {
                    if (condi.Compare == Operator.IsNull)
                    {
                        return string.Format(" {0} {1} ", columnAlias, condi.OperatorQuery);// + " = ? AND ");
                    }
                    else
                    {
                        return string.Format(" {0} {1} :{2} ", columnAlias, condi.OperatorQuery, colAtt.ColumName);// + " = ? AND ");
                    }
                }
            }
        }

        /// <summary>
        /// Creates the parameter.
        /// </summary>
        /// <param name="colAtt">The col att.</param>
        /// <param name="condition">The condition.</param>
        /// <param name="value">The value.</param>
        /// <param name="paraSurfix">The para surfix.</param>
        /// <returns></returns>
        protected override DbParameter OnCreateParameter(DbColumn colAtt, Condition condition, object value, string paraSurfix)
        {
            OracleParameter para = null;

            if (condition.IsCompareDateOnly)
            {
                para = new OracleParameter(colAtt.ColumName + paraSurfix, OracleType.VarChar, 10);
            }
            else
            {
                if (colAtt.ColumSize > 0)
                {
                    para = new OracleParameter(colAtt.ColumName + paraSurfix, (OracleType)colAtt.DbType, colAtt.ColumSize);
                }
                else
                {
                    para = new OracleParameter(colAtt.ColumName + paraSurfix, colAtt.DbType);
                }
            }

            if (condition.IsCompareDateOnly)
            {
                para.Value = ((DateTime)value).ToString("yyyy-MM-dd");
            }
            else
            {
                if (condition.Compare == Operator.Like)
                {
                    para.Value = '%' + value.ToString() + '%';
                }
                else
                {
                    para.Value = value;
                }
            }

            return para;
        }

        /// <summary>
        /// Sets the auto increase key.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        internal bool SetAutoIncreaseKey(IDbEntity entity, object value)
        {
            return this.SetDbSequenceValue(entity, value);
        }

        /// <summary>
        /// Gets the db sequence propery of entity.
        /// </summary>
        /// <param name="entity">The entity.</param>
        /// <returns>PropertyInfo value</returns>
        protected override bool SetDbSequenceValue(IDbEntity entity, object value)
        {
            // Get list of property in entity object
            PropertyInfo[] objPropers = entity.GetType().GetProperties();
            if (objPropers != null && objPropers.Length > 0)
            {
                DbColumn colAtt = null;
                OracleType oraType;
                foreach (PropertyInfo info in objPropers)
                {
                    colAtt = (DbColumn)Attribute.GetCustomAttribute(info, typeof(DbColumn), false);
                    if (colAtt != null && colAtt.IsUseDbSequence)
                    {
                        oraType = (OracleType)colAtt.DbType;
                        if (oraType == OracleType.Byte)
                        {
                            info.SetValue(entity, byte.Parse(value.ToString()), null);
                        }
                        else if (oraType == OracleType.Int16)
                        {
                            info.SetValue(entity, short.Parse(value.ToString()), null);
                        }
                        else if (oraType == OracleType.Int32)
                        {
                            info.SetValue(entity, int.Parse(value.ToString()), null);
                        }
                        else if (oraType == OracleType.Number)
                        {
                            info.SetValue(entity, decimal.Parse(value.ToString()), null);
                        }
                        return true;
                    }
                }

                return false;
            }

            return false;
        }
    }
}